﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace TByte.XnaHelper.Particles
{
    public abstract class ParticleModifier
    {
        #region Methods
        public abstract void Update(Particle particle);
        #endregion
    }

    public class AccelerationModifier : ParticleModifier
    {
        #region Fields
        Vector2 gravity;
        #endregion

        #region Methods
        public override void Update(Particle particle)
        {
            particle.Speed += gravity;
        }
        #endregion

        #region Constructors
        public AccelerationModifier(Vector2 gravity)
        {
            this.gravity = gravity;
        }
        #endregion

        #region Properties
        #endregion
    }
    public class RandomSpeedModifier : ParticleModifier
    {
        Vector2 minSpeed;
        Vector2 maxSpeed;

        public override void Update(Particle particle)
        {
            particle.Speed += new Vector2((maxSpeed.X - minSpeed.X) * (float)Manager.Random.NextDouble() + minSpeed.X, (maxSpeed.Y - minSpeed.Y) * (float)Manager.Random.NextDouble() + minSpeed.Y);
        }
        public RandomSpeedModifier(Vector2 minSpeed, Vector2 maxSpeed)
        {
            this.minSpeed = minSpeed;
            this.maxSpeed = maxSpeed;
        }
        public RandomSpeedModifier(Vector2 speed)
        {
            this.minSpeed = -speed;
            this.maxSpeed = speed;
        }
    }
    public class RotationModifier : ParticleModifier
    {
        #region Fields
        float rotationSpeed;
        #endregion

        #region Methods
        public override void Update(Particle particle)
        {
            particle.Rotation += rotationSpeed;
        }
        #endregion

        #region Constructors
        public RotationModifier(float rotationSpeed)
        {
            this.rotationSpeed = rotationSpeed;
        }
        #endregion

        #region Properties
        #endregion
    }
    public class OriginSpeedModifier : ParticleModifier
    {
        #region Fields
        float speed;
        #endregion

        #region Methods
        public override void Update(Particle particle)
        {
            Vector2 direction = particle.Parent.Position - particle.Position;

            particle.Speed += direction / direction.Length() * speed;
        }
        #endregion

        #region Constructors
        public OriginSpeedModifier(float speed)
        {
            this.speed = speed;
        }
        #endregion

        #region Properties
        #endregion
    }

    //Spawn Shapes
    public class CircleSpawnShapeModifier : ParticleModifier
    {
        #region Fields
        float width;
        float height;
        #endregion

        #region Methods
        public override void Update(Particle particle)
        {
            float angle = (float)(Math.PI * 2 * Manager.Random.NextDouble());
            particle.Position += new Vector2((float)Math.Cos(angle) * width / 2, (float)Math.Sin(angle) * height / 2);
        }
        #endregion

        #region Constructors
        public CircleSpawnShapeModifier(float width, float height)
        {
            this.width = width;
            this.height = height;
        }
        #endregion

        #region Properties
        #endregion
    }
    public class RoundSpawnShapeModifier : ParticleModifier
    {
        #region Fields
        float width;
        float height;
        #endregion

        #region Methods
        public override void Update(Particle particle)
        {
            float angle = (float)(Math.PI * 2 * Manager.Random.NextDouble());
            float radius = (float)Manager.Random.NextDouble();
            particle.Position += new Vector2((float)Math.Cos(angle) * width * radius / 2 , (float)Math.Sin(angle) * height * radius / 2);
        }
        #endregion

        #region Constructors
        public RoundSpawnShapeModifier(float width, float height)
        {
            this.width = width;
            this.height = height;
        }
        #endregion

        #region Properties
        #endregion
    }
    public class FilledRectangleSpawnShapeModifier : ParticleModifier
    {
        #region Fields
        float width;
        float height;
        #endregion

        #region Methods
        public override void Update(Particle particle)
        {
            particle.Position += new Vector2((float)(width * (0.5 - Manager.Random.NextDouble())), (float)(height * (0.5 - Manager.Random.NextDouble())));
        }
        #endregion

        #region Constructors
        public FilledRectangleSpawnShapeModifier(float width, float height)
        {
            this.width = width;
            this.height = height;
        }
        #endregion

        #region Properties
        #endregion
    }
    public class RectangleSpawnShapeModifier : ParticleModifier
    {
        #region Fields
        float width;
        float height;
        #endregion

        #region Methods
        public override void Update(Particle particle)
        {
            float point = (float)Manager.Random.NextDouble() * (2 * height + 2 * width);
            if (point <= width)
            {
                particle.Position += new Vector2(point - width / 2, -height / 2);
            }
            else if (point <= width + height)
            {
                particle.Position += new Vector2(width / 2, point - width - height / 2);
            }
            else if (point <= 2 * width + height)
            {
                particle.Position += new Vector2(point - width * 3 / 2 - height, height / 2);
            }
            else
            {
                particle.Position += new Vector2(-width / 2, point - 2 * width - height * 3 / 2);
            }
        }
        #endregion

        #region Constructors
        public RectangleSpawnShapeModifier(float width, float height)
        {
            this.width = width;
            this.height = height;
        }
        #endregion

        #region Properties
        #endregion
    }

    //Lerping
    public class ColorLerpModifier : ParticleModifier
    {
        #region Fields
        Color beginColor;
        Color endColor;
        #endregion

        #region Methods
        public override void Update(Particle particle)
        {
            particle.Color = Color.Lerp(beginColor, endColor, particle.LifeTime / particle.TimeToLive);
        }
        #endregion

        #region Constructors
        public ColorLerpModifier(Color beginColor, Color endColor)
        {
            this.beginColor = beginColor;
            this.endColor = endColor;
        }
        #endregion

        #region Properties
        #endregion
    }
    public class SizeLerpModifier : ParticleModifier
    {
        #region Fields
        float beginSize;
        float endSize;
        #endregion

        #region Methods
        public override void Update(Particle particle)
        {
            particle.Size = MathHelper.Lerp(beginSize, endSize, particle.LifeTime / particle.TimeToLive);
        }
        #endregion

        #region Constructors
        public SizeLerpModifier(float beginSize, float endSize)
        {
            this.beginSize = beginSize;
            this.endSize = endSize;
        }
        #endregion

        #region Properties
        #endregion
    }

    //Special modifiers
    public class SpawnModifier : ParticleModifier
    {
        #region Fields
        ParticleModifier modifier;
        #endregion

        #region Methods
        public override void Update(Particle particle)
        {
            if (particle.FirstUpdate)
            {
                modifier.Update(particle);
            }
        }
        #endregion

        #region Constructors
        public SpawnModifier(ParticleModifier mod)
        {
            modifier = mod;
        }
        #endregion

        #region Properties
        #endregion
    }
    public class TimeSpanModifier : ParticleModifier
    {
        #region Fields
        float begin;
        float end;
        ParticleModifier modifier;
        #endregion

        #region Methods
        public override void Update(Particle particle)
        {
            if (particle.LifeTime / particle.TimeToLive > begin && particle.LifeTime / particle.TimeToLive < end)
            {
                //Save current settings
                float ttl = particle.TimeToLive;
                float lifeTime = particle.LifeTime;

                //Replace settings for mods
                particle.LifeTime -= begin * particle.TimeToLive;
                particle.TimeToLive = (end - begin) * particle.TimeToLive;

                //Update particle
                modifier.Update(particle);

                //Reset settings
                particle.LifeTime = lifeTime;
                particle.TimeToLive = ttl;

            }
        }
        #endregion

        #region Constructors
        public TimeSpanModifier(float begin, float end, ParticleModifier mod)
        {
            this.begin = begin;
            this.end = end;
            this.modifier = mod;
        }
        #endregion

        #region Properties
        #endregion
    }
}
